using System;
using System.Collections.Generic;

// These dispatch on just the expr argument so they could be turned into ordinary
// virtual method calls. However this would require editing the Expression classes
// for every operation we may want to add that operates on them. But with 
// multimethods we can add new operations (e.g. print, pretty print, optimize)
// without distubning any existing code.
internal static class EvaluateOverloads
{
	// Disable the 'unused private method' warning for our overloads.
	#pragma warning disable 0169
	[Evaluate.Overload]
	private static double Evaluate(Dictionary<string, double> context, AssignmentExpression expr)
	{
		double value = global::Evaluate.Invoke(context, expr.Value);
		context[expr.Name] = value;
		return value;
	}
	
	[Evaluate.Overload]
	private static double Evaluate(Dictionary<string, double> context, BinaryExpression expr)
	{
		double value;
		
		switch (expr.Operator)
		{
			case "+":
				value = global::Evaluate.Invoke(context, expr.Left) + global::Evaluate.Invoke(context, expr.Right);
				break;
			
			case "-":
				value = global::Evaluate.Invoke(context, expr.Left) - global::Evaluate.Invoke(context, expr.Right);
				break;
			
			case "*":
				value = global::Evaluate.Invoke(context, expr.Left) * global::Evaluate.Invoke(context, expr.Right);
				break;
			
			case "/":
				value = global::Evaluate.Invoke(context, expr.Left) / global::Evaluate.Invoke(context, expr.Right);
				break;
			
			default:
				throw new InvalidOperationException("Bad binary operator: " + expr.Operator);
		}
		
		return value;
	}
	
	[Evaluate.Overload]
	private static double Evaluate(Dictionary<string, double> context, LiteralExpression expr)
	{
		return expr.Value;
	}
	
	[Evaluate.Overload]
	private static double Evaluate(Dictionary<string, double> context, VariableExpression expr)
	{
		double value;
		if (!context.TryGetValue(expr.Name, out value))
			throw new InvalidOperationException("Uninitialized variable: " + expr.Name);
		
		return value;
	}
	#pragma warning restore 0169
}
